﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Microsoft.WindowsAzure.StorageClient;
using Microsoft.WindowsAzure;

namespace AzurePutBllockExample
{
    public class AzureBlobUtil
    {
        private const int MaxBlockSize = 4000000; // Approx. 4MB chunk size

        public Uri UploadBlob(string filePath, CloudStorageAccount account, string containerName)
        {
            byte[] fileContent = File.ReadAllBytes(filePath);
            string blobName = Path.GetFileName(filePath);

            return UploadBlob(fileContent, account, containerName, blobName);
        }

        public Uri UploadBlob(byte[] fileContent, CloudStorageAccount account, string containerName, string blobName)
        {
            CloudBlobClient blobclient = account.CreateCloudBlobClient();

            CloudBlobContainer container = blobclient.GetContainerReference(containerName);
            container.CreateIfNotExist();

            CloudBlockBlob blob = container.GetBlockBlobReference(blobName);

            HashSet<string> blocklist = new HashSet<string>();
            foreach (FileBlock block in GetFileBlocks(fileContent))
            {
                blob.PutBlock(
                    block.Id,
                    new MemoryStream(block.Content, true),
                    null
                    );

                blocklist.Add(block.Id);
            }

            blob.PutBlockList(blocklist);

            return blob.Uri;
        }

        private IEnumerable<FileBlock> GetFileBlocks(byte[] fileContent)
        {
            HashSet<FileBlock> hashSet = new HashSet<FileBlock>();
            if (fileContent.Length == 0)
                return new HashSet<FileBlock>();

            int blockId = 0;
            int ix = 0;

            int currentBlockSize = MaxBlockSize;

            while (currentBlockSize == MaxBlockSize)
            {
                if ((ix + currentBlockSize) >  fileContent.Length)
                    currentBlockSize = fileContent.Length - ix;

                byte[] chunk = new byte[currentBlockSize];
                Array.Copy(fileContent, ix, chunk, 0, currentBlockSize);

                hashSet.Add(
                    new FileBlock()
                    {
                        Content = chunk,
                        Id = Convert.ToBase64String(System.BitConverter.GetBytes(blockId))
                    });

                ix += currentBlockSize;
                blockId++;
            }

            return hashSet;
        }

        public Stream DownloadBlobAsStream(CloudStorageAccount account, string blobUri)
        {
            Stream stream = new MemoryStream();

            CloudBlobClient blobclient = account.CreateCloudBlobClient();
            CloudBlockBlob blob = blobclient.GetBlockBlobReference(blobUri);

            if (blob != null)
                blob.DownloadToStream(stream);

            return stream;
        }

        public string DownloadBlobAsFile(CloudStorageAccount account, string blobUri)
        {
            Stream stream = DownloadBlobAsStream(account, blobUri);
            string fileName = "Blob.file"; // Please change file name based on your need

            if (stream != null)
            {
                FileStream fileStream = File.Create(fileName);
                stream.Position = 0;
                stream.CopyTo(fileStream);
                fileStream.Close();

                return fileName;
            }

            return string.Empty;
        }
    }

    internal class FileBlock
    {
        public string Id
        {
            get;
            set;
        }

        public byte[] Content
        {
            get;
            set;
        }
    }
}
